/** @file random.h
 *
 *  @author Dongryeol Lee (drselee@gmail.com)
 */

#ifndef CORE_UTIL_RANDOM_H
#define CORE_UTIL_RANDOM_H

#include <ctime>
#include <gsl/gsl_rng.h>

namespace core {
namespace util {
class Random {
  private:

    gsl_rng *rng_;

  public:

    void Init(const gsl_rng_type *gsl_type, unsigned int seed) {
      rng_ = gsl_rng_alloc(gsl_type);
      gsl_rng_set(rng_, seed);
    }

    Random(const gsl_rng_type *gsl_type, unsigned int seed) {
      this->Init(gsl_type, seed);
    }

    Random() {
      this->Init(gsl_rng_mt19937, time(NULL));
    }

    ~Random() {
      gsl_rng_free(rng_);
    }

    unsigned long int Integer() {
      return gsl_rng_get(rng_);
    }

    double Uniform() {
      return gsl_rng_uniform(rng_);
    }

    double Uniform(double low, double high) {
      return low + (high - low) * (this->Uniform());
    }

    unsigned long int Integer(unsigned long int end_exclusive) {
      return gsl_rng_uniform_int(rng_, end_exclusive);
    }

    unsigned long int Integer(
      unsigned long int begin_inclusive, unsigned long int end_exclusive) {

      return begin_inclusive +
             gsl_rng_uniform_int(rng_, end_exclusive - begin_inclusive);
    }
};
}
}

#endif
